package org.frogs.algo;

import java.util.ArrayList;
import java.util.List;

public class Calculator {
	public static Double getFrogDistance(Frog firstFrog, Frog secondFrog) {
		return Math
				.sqrt(Math.pow(
						Math.abs(firstFrog.getCenterX()
								- secondFrog.getCenterX()), 2)
						+ Math.pow(Math.abs(
								firstFrog.getCenterY()
										- secondFrog.getCenterY()), 2));
	}

	public static Double getBulletDistance(Frog myFrog, Bullet enemyBullet) {
		return Math.sqrt(Math.pow(
				Math.abs(myFrog.getCenterX() - enemyBullet.getCurrentX()), 2)
				+ Math.pow(Math.abs(myFrog.getCenterY() - enemyBullet.getCurrentY()), 2));
	}

	public static Double getNextBulletDistance(Frog myFrog, Bullet enemyBullet) {
		return Math.sqrt(Math.pow(
				Math.abs(myFrog.getCenterX() - enemyBullet.getNextX()), 2)
				+ Math.pow(Math.abs(myFrog.getCenterY() - enemyBullet.getNextY()), 2));
	}

	public static boolean isEnemyBullet(Frog myFrog, Bullet enemyBullet) {
		return getBulletDistance(myFrog, enemyBullet) > getNextBulletDistance(
				myFrog, enemyBullet);
	}

	// THIS METHOD IS NOT WORKING AND WILL NOT BE USED FOR NOW!.
	public static List<Double> simulateBullet(Frog myFrog, Bullet bullet) {
		List<Double> result = new ArrayList<Double>();
		
		if(isInsideFrog(myFrog, bullet.getNextX(), bullet.getNextY())) {
			result.add(bullet.getNextX());
			result.add(bullet.getNextY());
		} else {
		if(isEnemyBullet(myFrog, bullet)) {
			Double currBulletX = bullet.getCurrentX();
			Double currBulletY = bullet.getCurrentY();
			Double nextBulletX = bullet.getNextX();
			Double nextBulletY = bullet.getNextY();
			
			Double currDistance;
			Double nextDistance;
			do {
			currDistance = Math.sqrt(Math.pow(
					Math.abs(myFrog.getCenterX() - currBulletX), 2)
					+ Math.pow(Math.abs(myFrog.getCenterY() - currBulletY), 2));
			nextDistance = Math.sqrt(Math.pow(
					Math.abs(myFrog.getCenterX() - nextBulletX), 2)
					+ Math.pow(Math.abs(myFrog.getCenterY() - nextBulletY), 2));
			
			List<Double> future = getBulletFutureCoordinates(currBulletX, currBulletY, nextBulletX, nextBulletY);
			if (isInsideFrog(myFrog, future.get(0), future.get(1))) {
				result.add(future.get(0));
				result.add(future.get(1));
				return result;
			}
			
			currBulletX = nextBulletX;
			currBulletY = nextBulletY;
			nextBulletX = future.get(0);
			nextBulletY = future.get(1);
			} while (currDistance < nextDistance);
		}
		}
		return result;
	}
	
	public static Double getCentralDistance (Frog frog) {
		return Math.sqrt(Math.pow(frog.getCenterX(), 2) + Math.pow(frog.getCenterY(), 2));
	}
	
	public static Double getMarginalDistance (Frog frog, FrogPool pool) {
		return pool.getPoolRadius() - getCentralDistance(frog);
	}
	
	public static Bullet getDangerousBullet(FrogPool pool) {
		if (pool.getBulletList().isEmpty()) {
			return null;
		} else {
			Bullet mostDangerousBullet = null;
			for(Bullet currentBullet : pool.getBulletList()) {
				if (isEnemyBullet(pool.getMyFrog(), currentBullet)) {
					if (mostDangerousBullet == null) {
						mostDangerousBullet = currentBullet;
					} else {
						if (getBulletDistance(pool.getMyFrog(), currentBullet) < getBulletDistance(pool.getMyFrog(), mostDangerousBullet)) {
							mostDangerousBullet = currentBullet;
						}
					}
				}
			}
			return mostDangerousBullet;
		}
	}

	// PRIVATE USE ONLY V.I.P
	private static List<Double> getBulletFutureCoordinates(Double currBulletX,
			Double currBulletY, Double nextBulletX, Double nextBulletY) {
		Double futureX = currBulletX + 2 * (currBulletX - nextBulletX);
		Double futureY = currBulletY + 2 * (currBulletY - nextBulletY);

		List<Double> result = new ArrayList<Double>();
		result.add(futureX);
		result.add(futureY);
		return result;
	}
	
	private static boolean isInsideFrog(Frog myFrog, Double bulletX, Double bulletY) {
		Double distance = Math.sqrt(Math.pow(
				Math.abs(myFrog.getCenterX() - bulletX), 2)
				+ Math.pow(Math.abs(myFrog.getCenterY() - bulletY), 2));
		
		return distance <= 3.5;
	}
}
